#include "HttpClient.h"
#include "Marshal2.h"

using namespace System::Text;
using namespace System::IO;

namespace Ws2Com {
	namespace Http {
		HttpClient::HttpClient() {
			client = http_client_new();
		}

		HttpClient::HttpClient(WebProxy^ proxy) : HttpClient() {
			if (!proxy) return;
			this->proxy = proxy;

			if (proxy->HttpProxy) {
				http_client_set_http_proxy(client, Marshal2::ClrStringToUTF8CString(proxy->HttpProxy->Host), proxy->HttpProxy->Port);
			}
			if (proxy->HttpsProxy) {
				http_client_set_https_proxy(client, Marshal2::ClrStringToUTF8CString(proxy->HttpsProxy->Host), proxy->HttpsProxy->Port);
			}
		}

		HttpClient::~HttpClient() {
			if (client) {
				http_client_del(client);
				client = NULL;
			}
		}
		void HttpClient::SetProxy(HttpRequest req) {
			if (!this->proxy) return;

			if (req.isHttps()) {
				req.SetProxy(Marshal2::ClrStringToUTF8CString(this->proxy->HttpsProxy->Host), this->proxy->HttpsProxy->Port);
			} else {
				req.SetProxy(Marshal2::ClrStringToUTF8CString(this->proxy->HttpProxy->Host), this->proxy->HttpProxy->Port);
			}
		}

		String^ HttpClient::Send(HttpWebRequest^ request) {
			HttpRequest req;
			req.method = (http_method)(int)request->Uri->Method;

			req.url = Marshal2::ClrStringToUTF8CString(request->Uri->Url);

			if (request->Headers && request->Headers->Count > 0) {
				for each (String ^ k in request->Headers->AllKeys) {
					char* key = Marshal2::ClrStringToUTF8CString(k);
					req.headers[key] = Marshal2::ClrStringToUTF8CString(request->Headers[k]);
				}
			}

			req.redirect = request->Redirect;
			req.timeout = request->Timeout;
			SetProxy(req);
			if (request->Body && request->Body->Length > 0) {
				req.body = Marshal2::ClrStringToUTF8CString(request->Body);
			}

			HttpResponse resp;
			int ret = http_client_send(client, &req, &resp);
			if (ret == 0) {
				std::cout << resp.body.c_str() << std::endl;
				return gcnew String(resp.body.c_str(), 0, resp.body.length(), Encoding::UTF8);
			} else {
				return "";
			}
		}
		HttpWebResponse^ HttpClient::SendToStream(HttpWebRequest^ request) {
			HttpRequest req;
			req.method = (http_method)(int)request->Uri->Method;

			req.url = Marshal2::ClrStringToUTF8CString(request->Uri->Url);

			if (request->Headers && request->Headers->Count > 0) {
				for each (String ^ k in request->Headers->AllKeys) {
					char* key = Marshal2::ClrStringToUTF8CString(k);
					req.headers[key] = Marshal2::ClrStringToUTF8CString(request->Headers[k]);
				}
			}

			req.redirect = request->Redirect;
			req.timeout = request->Timeout;
			SetProxy(req);
			if (request->Body && request->Body->Length > 0) {
				req.body = Marshal2::ClrStringToUTF8CString(request->Body);
			}
			HttpResponse resp;
			int ret = http_client_send(client, &req, &resp);
			if (ret == 0) {
				HttpWebResponse^ response = gcnew HttpWebResponse();
				response->Body = gcnew MemoryStream(Marshal2::UTF8CharToClrArrayChar(resp.body));
				response->Headers = gcnew NameValueCollection();
				for (const auto& kv : resp.headers) {
					response->Headers->Add(gcnew String(kv.first.c_str()), gcnew String(kv.second.c_str()));
				}
				return response;
			} else {
				return nullptr;
			}
		}

		Stream^ HttpClient::SendToStream(HttpWebRequest^ request, [Runtime::InteropServices::Out]bool% compress) {
			HttpRequest req;
			req.method = (http_method)(int)request->Uri->Method;

			req.url = Marshal2::ClrStringToUTF8CString(request->Uri->Url);

			if (request->Headers && request->Headers->Count > 0) {
				for each (String ^ k in request->Headers->AllKeys) {
					char* key = Marshal2::ClrStringToUTF8CString(k);
					req.headers[key] = Marshal2::ClrStringToUTF8CString(request->Headers[k]);
				}
			}

			req.redirect = request->Redirect;
			req.timeout = request->Timeout;
			SetProxy(req);
			if (request->Body && request->Body->Length > 0) {
				req.body = Marshal2::ClrStringToUTF8CString(request->Body);
			}
			HttpResponse resp;
			int ret = http_client_send(client, &req, &resp);
			if (ret == 0) {
				MemoryStream^ stream = gcnew MemoryStream(Marshal2::UTF8CharToClrArrayChar(resp.body));
				compress = resp.headers["Content-Encoding"] == "gzip" || resp.headers["content-encoding"] == "gzip";
				return stream;
			} else {
				return nullptr;
			}
		}
	}
}
